<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>

  <script>
    // 立即调用当前函数, 并指定其this为第一个参数
    Function.prototype.call = function(thisObj, ...args) {
      console.log('call()')
      // 当前函数  调用call方法的函数   就是this
      // this是不是fn?
      // console.log(this)
      // return this(...args)  // fn函数中的this不对

      // this.call(thisObj, ...args)  // 死循环了

      if (thisObj===undefined || thisObj===null) {
        // thisObj = window
        return this(...args)
      }

      // 将当前函数添加为thisObj的方法
      thisObj.tempFn = this
      // 通过thisObj来调用这个方法
      const result = thisObj.tempFn(...args)
      // 删除这个方法
      delete thisObj.tempFn

      return result
    }

    Function.prototype.apply = function(thisObj, args) {
      console.log('apply()')

      if (thisObj===undefined || thisObj===null) {
        // thisObj = window
        return this(...args)
      }

      // 将当前函数添加为thisObj的方法
      thisObj.tempFn = this
      // 通过thisObj来调用这个方法
      const result = thisObj.tempFn(...args)
      // 删除这个方法
      delete thisObj.tempFn

      return result
    }

    // bind返回一个新函数, 新函数内部会调用原函数, 并指定原函数中的this为第一个参数对象
    Function.prototype.bind = function (thisObj, ...args) {
      console.log('bind()')
      // this就是原函数
      return (...args2) => {
        return this.call(thisObj, ...args, ...args2)
      }
    }

    function call(fn, thisObj, ...args) {
      console.log('call()')
      // 当前函数  调用call方法的函数   就是this
      // this是不是fn?
      // console.log(this)
      // return this(...args)  // fn函数中的this不对

      // this.call(thisObj, ...args)  // 死循环了

      if (thisObj===undefined || thisObj===null) {
        // thisObj = window
        return fn(...args)
      }

      // 将当前函数添加为thisObj的方法
      thisObj.tempFn = fn
      // 通过thisObj来调用这个方法
      const result = thisObj.tempFn(...args)
      // 删除这个方法
      delete thisObj.tempFn

      return result
    }

    // 对象快照: 打印对象时, 对象的样子: 当前对象的状态
  </script>

  <script>
    var m = 2
    function fn(a, b) {
      console.log(this, a, b);
      return a + b
    }
    const obj = {m: 1}

   
    // console.log(fn.call(obj, 3, 4))
    // console.log(fn.call(undefined, 3, 4)) // 第一个参数是undefined/null时, this为window
   
    // console.log(fn.apply(obj, [3, 4]))
    // console.log(fn.apply(undefined, [3, 4]))

    // 绑定this和参数
    // bind返回一个新函数, 新函数内部会调用原函数, 并指定原函数中的this为第一个参数对象
    console.log(fn.bind(obj)(3, 4))
    console.log(fn.bind(undefined)(3, 4))
    console.log(fn.bind(obj, 5)(3, 4))
    console.log(fn.bind(obj, 5, 6)(3, 4))

    
  </script>
</body>
</html>